//
//  CZEmotionManager.swift
//  表情包数据
//
//  Created by youyoumacmini3 on 2017/8/4.
//  Copyright © 2017年 youyoumacmini3. All rights reserved.
//

import UIKit

// 表情管理器
class CZEmotionManager {
    
    // 便于表情的复用，建立一个单例，只加载一次表情数据
    // 表情管理器单例
    static let shared = CZEmotionManager()
    
    // 表情素材的 bundle
    lazy var bundle: Bundle = {
        let path = Bundle.main.path(forResource: "HMEmoticon.bundle", ofType: nil)
        return Bundle(path: path!)!
        
    }()
    
    
    /// 表情包的懒加载数组 - 第一个数组是最近表情，加载之后，表情数组为空
    lazy var packages = [CZEmotionPackage]()
    
    // 构造函数，如果在 init 之前增加 private 修饰符，可以要求调用者必须通过 shared 访问对象
    // OC 需要重写 allocWithZone 方法
    private init() {
        loadPackages()
    }
    
    // 添加最近使用的表情
    // em: 选中的表情
    func recentEmotion(em: CZEmotion) {
        
        // 1. 增加表情的使用次数
        em.times += 1
        
        // 2. 判断是否已经记录了该表情，如果没有记录，添加记录
        if !packages[0].emotions.contains(em) {
            packages[0].emotions.append(em)
        }
        
        // 3. 根据使用次数排序，使用次数高的排序靠前
        // 对当前数组排序
        
        //packages[0].emotions.sort { (em1, em2) -> Bool in
        //    return em1.times > em2.times
        //}
        
        // 在 swift 中，如果闭包只有一个 return，参数可以省略，参数名用 $0...替代
        // 所以上述排序可想、如下写法
        packages[0].emotions.sort { $0.times > $1.times }
        
        // 4. 判断表情数组是否超出 20，如果超出，删除末尾的表情
        if packages[0].emotions.count > 20 {
            packages[0].emotions.removeSubrange(20..<packages[0].emotions.count)
        }
        
        
        
    }
    
}


// MARK: - 表情字符串处理
extension CZEmotionManager {
    
    
    /// 将给定的字符串转换成属性文本
    ///
    /// - 关键点： 要匹配结果倒序替换属性文本
    ///
    /// - Parameter string: 完整字符串
    /// - Returns: 属性文本
    func emotionString(string: String, font: UIFont) -> NSAttributedString {
        
        // let attrString = NSAttributedString(string: string)
        // NSAttributedString 不可变，用这个无法替换表情
        let attrString = NSMutableAttributedString(string: string)
        
        // 1. 建立正则表达式，过滤所有的表情文字
        // []、() 都是正则表达式关键字，如果需要参加匹配，需要转义
        let pattern = "\\[.*?\\]"
        
        guard let regx = try? NSRegularExpression(pattern: pattern, options: []) else {
            return attrString
        }
        
        // 2. 匹配所有项
        let maches = regx.matches(in: string, options: [], range: NSRange(location: 0, length: attrString.length))
        
        // 3. 遍历所有匹配结果
        for m in maches.reversed() {
            let r = m.rangeAt(0)
            print(r.location)
            print(r.length)
            
            
            let subStr = (attrString.string as NSString).substring(with: r)
            
            // 1》使用 subStr 查找对应的表情符号
            if let em = CZEmotionManager.shared.findEmotion(string: subStr) {
                print(em)
                // 2》使用表情符号中的属性文本，替换原有的属性文本的内容
                attrString.replaceCharacters(in: r, with: em.imageText(font: font))
            }
        }
        
        // 4. 统一设置一遍字符串的属性 - 除了需要设置字体，还需要设置颜色
        attrString.addAttributes([NSFontAttributeName: font,
                                  NSForegroundColorAttributeName: UIColor.darkGray], range: NSRange(location: 0, length: attrString.length))
        
        
        return attrString
    }

    
    
    
    
    /// 根据 string [爱你] 在所有的表情符号中查找对应的表情模型对象
    ///
    /// - Returns: 如果找到，返回表情模型
    /// - Returns: 否则，返回 nil
    func findEmotion(string: String) -> CZEmotion? {
        //1. 遍历表情包
        // OC 中遍历数组使用 [谓词]
        // swift 中更简单
        for p in packages {
            // 在表情数组中过滤 string
            // 三种方法如下：分别是三种不同的尾随闭包的写法
            // 方法 1、
//            let result = p.emotions.filter({ (em) -> Bool in
//                return em.chs == string
//            })
            
            // 方法 2、 - 尾随闭包
//            let result = p.emotions.filter() { (em) -> Bool in
//                return em.chs == string
//            }
            
            // 方法 3、 - 如果闭包中只有一句，并且是返回
            // 1> 闭包格式定义可以省略
            // 2> 参数省略后使用 $0, $1... 依次替代原有的参数
            // 3> return 也可以省略
            let result = p.emotions.filter() { $0.chs == string }
            
            
            // 判断结果数组的数量
            if result.count == 1 {
                return result[0]
            }
        }
    
        return nil
    }
}


// MARK: - 加载表情包数据处理
private extension CZEmotionManager {
    
    func loadPackages() {
        // 读取 emoticon.plist
        // 只要按照 bundle 默认的目录结构设定，就可以直接读取 Resource 目录下的文件
        // 所以在下面自定义了一个 bundle 来越过其他文件直接取 plistPath 从而拿到array
        guard let path = Bundle.main.path(forResource: "HMEmoticon.bundle", ofType: nil),
              let bundle = Bundle(path: path),
              let plistPath = bundle.path(forResource: "emoticons.plist", ofType: nil),
              let array = NSArray(contentsOfFile: plistPath) as? [[String: String]],
              let models = NSArray.yy_modelArray(with: CZEmotionPackage.self, json: array) as? [CZEmotionPackage]
            else {
            return
        }
        
        // 设置表情包数据
        // 使用 += 不需要再次给 packages 分配控件，直接追加数据
        packages += models
        
        
        print(packages)
    }
    
}
